﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;

using Tradex;
using Tradex.Market;
using Tradex.Messages;

namespace Tradex.Connectivity.DataLog {
    
    /// <summary>
    /// The DataLogExtensions extend the TextWrite and TextReader classes with methods to read and write the
    /// contents of the different DataLog log files. As such, this class is the one place where all log file
    /// generation and parsing code is centralized.
    /// </summary>
    public static class DataLogExtensions {

        /// <summary>
        /// Writes an entry in the InstrumentLog format, which contains all instrument updates.
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="update"></param>
        public static void WriteInstrumentLogEntry(this TextWriter writer, InstrumentUpdateMessage update) {
            if (writer == null) {
                throw new ArgumentException("value can not be null", "writer");
            }
            if (update == null) {
                throw new ArgumentException("value can not be null", "update");
            }
            Contract.EndContractBlock();

            if (update.InstrumentInfo == null && update.InstrumentPricing == null) {
                return;
            }
            writer.WriteLine(
                String.Format (
                    CultureInfo.InvariantCulture, "@ {0} {1}",
                    update.InstrumentKey.Market, update.InstrumentKey.Instrument
                )
            );
            if (update.InstrumentInfo != null) {
                writer.WriteLine(update.InstrumentInfo);
            }
            if (update.InstrumentPricing != null) {
                writer.WriteLine(update.InstrumentPricing);
            }
        }

        /// <summary>
        /// Writes out a log entry for a the Activity log (which contains market activity updates). The ActivityLog
        /// contains one print per line, starting with the timestamp.
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="update"></param>
        public static void WriteActivityLogEntry(this TextWriter writer, InstrumentActivityUpdateMessage update) {
            if (writer == null) {
                throw new ArgumentException("value can not be null", "writer");
            }
            if (update == null) {
                throw new ArgumentException("value can not be null", "update");
            }
            Contract.EndContractBlock();

            Activity activity = update.Activity;
            string retval = null;
            switch (activity.ActivityType) {
                case ActivityType.Mode:
                    retval = String.Format(
                        CultureInfo.InvariantCulture, "{0:yyyy-MM-dd HH:mm:ss.ffffff} {1} {2} / {3}",
                        activity.Timestamp, activity.ActivityType, activity.Mode, activity.ModeCode
                    );
                    break;
                case ActivityType.Volume:
                    retval = String.Format(
                        CultureInfo.InvariantCulture, "{0:yyyy-MM-dd HH:mm:ss.ffffff} {1} {2}",
                        activity.Timestamp, activity.ActivityType, activity.Volume
                    );
                    break;
                case ActivityType.Close:
                case ActivityType.Open:
                case ActivityType.High:
                case ActivityType.Low:
                case ActivityType.Settlement:
                case ActivityType.Closing:
                case ActivityType.Opening:
                    retval = String.Format(
                        CultureInfo.InvariantCulture, "{0:yyyy-MM-dd HH:mm:ss.ffffff} {1} {2}",
                        activity.Timestamp, activity.ActivityType, activity.Price
                    );
                    break;
                case ActivityType.Trade:
                case ActivityType.BestBid:
                case ActivityType.BestAsk:
                case ActivityType.Ask:
                case ActivityType.Bid:
                    retval = String.Format(
                        CultureInfo.InvariantCulture, "{0:yyyy-MM-dd HH:mm:ss.ffffff} {1} {2} @ {3}",
                        activity.Timestamp, activity.ActivityType, activity.Volume, activity.Price
                    );
                    break;
            }
            writer.WriteLine (retval);
        }

        /// <summary>
        /// Writes an entry in the OrderLog format, which contains all order updates that pass through the system.
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="update"></param>
        public static void WriteOrderLogEntry(this TextWriter writer, OrderUpdateMessage update) {
            if (writer == null) {
                throw new ArgumentException("value can not be null", "writer");
            }
            if (update == null) {
                throw new ArgumentException("value can not be null", "update");
            }
            Contract.EndContractBlock();

            if (update.Progress == null && update.Execution == null) {
                return;
            }

            writer.WriteLine(
                String.Format(
                    CultureInfo.InvariantCulture, "@ {0} {1}",
                    update.OrderKey, update.ConnectionKey
                )
            );

            if (update.Progress != null) {
                writer.WriteLine(update.Progress);
            }

            if (update.Execution != null) {
                writer.WriteLine(update.Execution);
            }
        }

        /// <summary>
        /// Writes an entry in the ExecutionLog format, which contains all execution updates that pass through the system.
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="update"></param>
        public static void WriteExecutionLogEntry(this TextWriter writer, OrderUpdateMessage update) {
            if (writer == null) {
                throw new ArgumentException("value can not be null", "writer");
            }
            if (update == null) {
                throw new ArgumentException("value can not be null", "update");
            }
            Contract.EndContractBlock();

            if (update.Execution == null) {
                return;
            }

            writer.WriteLine(
                String.Format(
                    CultureInfo.InvariantCulture, "@ {0} {1}",
                    update.OrderKey, update.ConnectionKey
                )
            );
            writer.WriteLine(update.Execution);
        }

        /// <summary>
        /// Reads an entry in the InstrumentLog format, which contains all instrument updates.
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        public static InstrumentUpdateMessage ReadInstrumentLogEntry(this TextReader reader) {
            if (reader == null) {
                throw new ArgumentException("value can not be null", "reader");
            }
            Contract.EndContractBlock();

            return null;
        }

        /// <summary>
        /// Reads an entry in the ActivityLog format, which contains all market activity updates.
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        public static InstrumentActivityUpdateMessage ReadActivityLogEntry(this TextReader reader) {
            if (reader == null) {
                throw new ArgumentException("value can not be null", "reader");
            }
            Contract.EndContractBlock();

            return null;
        }

        /// <summary>
        /// Reads an entry in the OrderLog format, which contains all order updates updates.
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        public static OrderUpdateMessage ReadOrderLogEntry(this TextReader reader) {
            if (reader == null) {
                throw new ArgumentException("value can not be null", "reader");
            }
            Contract.EndContractBlock();

            return null;
        }

        /// <summary>
        /// Reads an entry in the ExecutionLog format, which contains all order execution updates.
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        public static OrderUpdateMessage ReadExecutionLogEntry(this TextReader reader) {
            if (reader == null) {
                throw new ArgumentException("value can not be null", "reader");
            }
            Contract.EndContractBlock();

            return null;
        }

    }

}
